package field;

import java.awt.Point;

import building.Building;
import building.Building.BuildingType;

public class Field implements Cloneable {

	public enum FieldType {
		EMPTY, TIBERIUM, CRYSTAL
	}

	private final FieldType fieldType;
	private final Point position;

	private Building building = null;
	private Field[] neighborFields;

	public Field(FieldType fieldType, Point position) {
		this.fieldType = fieldType;
		this.position = position;
		neighborFields = new Field[0];
	}

	public FieldType getFieldType() {
		return fieldType;
	}

	public Point getPosition() {
		return position;
	}

	public synchronized boolean isCovered() {
		return building != null;
	}

	public synchronized void removeBuilding() {
		building = null;
	}

	public synchronized boolean setBuilding(Building building) {
		if (building == null) {
			this.building = null;
			return true;
		}

		if (!building.canBeBuildOnThisFieldType(fieldType)) {
			return false;
		}
		this.building = building;
		return true;
	}

	public void setNeighborFields(Field[] neighborFields) {
		this.neighborFields = neighborFields;
	}

	public synchronized double calcValue() {
		double value = 0;

		if (!isCovered()) {
			return 0;
		}

		switch (fieldType) {
		case CRYSTAL:
		case TIBERIUM: {
			// a silo has to be near the field. Every silo more has not much
			// effect.

			int siloCounter = 0;
			for (int i = 0; i < neighborFields.length; i++) {
				Field neighbor = neighborFields[i];
				if (neighbor.fieldType == FieldType.EMPTY && neighbor.isCovered() && neighbor.building.getBuildingType() == BuildingType.SILO) {
					siloCounter++;
					if (siloCounter < 3) {
						value = value + 40;
					} else if (siloCounter == 3) {
						value = value + 20;
					}
				}
			}
			break;
		}

		case EMPTY:
			switch (building.getBuildingType()) {

			case POWER_PLANT: {
				int crystalCounter = 0;
				int accumulatorCounter = 0;
				for (int i = 0; i < neighborFields.length; i++) {
					Field neighbor = neighborFields[i];
					if (neighbor.fieldType == FieldType.CRYSTAL) {
						crystalCounter++;
						if (crystalCounter <= 4) {
							value = value + 25;
						}
					} else if (neighbor.fieldType == FieldType.EMPTY && neighbor.isCovered()
							&& neighbor.building.getBuildingType() == BuildingType.ACCUMULATOR) {
						accumulatorCounter++;
						if (accumulatorCounter < 3) {
							value = value + 40;
						} else if (accumulatorCounter == 3) {
							value = value + 20;
						}
					}
				}
				break;
			}

			case REFINERY: {
				int tiberiumCounter = 0;
				int powerPlantCounter = 0;
				for (int i = 0; i < neighborFields.length; i++) {
					Field neighbor = neighborFields[i];
					if (neighbor.fieldType == FieldType.TIBERIUM) {
						tiberiumCounter++;
						if (tiberiumCounter <= 4) {
							value = value + 25;
						}
					} else if (neighbor.fieldType == FieldType.EMPTY && neighbor.isCovered()
							&& neighbor.building.getBuildingType() == BuildingType.POWER_PLANT) {
						powerPlantCounter++;
						if (powerPlantCounter < 3) {
							value = value + 40;
						} else if (powerPlantCounter == 3) {
							value = value + 20;
						}
					}
				}
				break;
			}

			case SILO:
			case ACCUMULATOR:
				value = 0;
				break;

			// should never reach this case
			case HARVESTER:
				throw new RuntimeException("Shoud never reach this case");
			default:
				break;
			}

			break;

		default:
			break;
		}

		return value;
	}

	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("FieldType: ");
		sb.append(fieldType);
		sb.append("; Pos: ");
		sb.append(position.x);
		sb.append(":");
		sb.append(position.y);
		sb.append("; IsCovered: ");
		sb.append(isCovered());
		if (isCovered()) {
			sb.append("; ");
			sb.append(building);
		}

		return sb.toString();
	}

	@Override
	public Field clone() {
		try {
			return (Field) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}
}
